{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# Let printing work the same in Python 2 and 3\n",
    "from __future__ import print_function\n",
    "# Turning on inline plots -- just for use in ipython notebooks.\n",
    "import matplotlib\n",
    "matplotlib.use('nbagg')\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Artists\n",
    "Anything that can be displayed in a Figure is an [`Artist`](http://matplotlib.org/users/artists.html). There are two main classes of Artists: primatives and containers. Below is a sample of these primitives."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "Show examples of matplotlib artists\n",
    "http://matplotlib.org/api/artist_api.html\n",
    "\n",
    "Several examples of standard matplotlib graphics primitives (artists)\n",
    "are drawn using matplotlib API. Full list of artists and the\n",
    "documentation is available at\n",
    "http://matplotlib.org/api/artist_api.html\n",
    "\n",
    "Copyright (c) 2010, Bartosz Telenczuk\n",
    "\n",
    "License: This work is licensed under the BSD. A copy should be\n",
    "included with this source code, and is also available at\n",
    "http://www.opensource.org/licenses/bsd-license.php\n",
    "\"\"\"\n",
    "\n",
    "from matplotlib.collections import PatchCollection\n",
    "import matplotlib.path as mpath\n",
    "import matplotlib.patches as mpatches\n",
    "import matplotlib.lines as mlines\n",
    "\n",
    "fig, ax = plt.subplots(1, 1, figsize=(7,7))\n",
    "\n",
    "# create 3x3 grid to plot the artists\n",
    "pos = np.mgrid[0.2:0.8:3j, 0.2:0.8:3j].reshape(2, -1)\n",
    "patches = []\n",
    "\n",
    "# add a circle\n",
    "art = mpatches.Circle(pos[:, 0], 0.1, ec=\"none\")\n",
    "patches.append(art)\n",
    "plt.text(pos[0, 0], pos[1, 0] - 0.15, \"Circle\", ha=\"center\", size=14)\n",
    "\n",
    "# add a rectangle\n",
    "art = mpatches.Rectangle(pos[:, 1] - [0.025, 0.05], 0.05, 0.1, ec=\"none\")\n",
    "patches.append(art)\n",
    "plt.text(pos[0, 1], pos[1, 1] - 0.15, \"Rectangle\", ha=\"center\", size=14)\n",
    "\n",
    "# add a wedge\n",
    "wedge = mpatches.Wedge(pos[:, 2], 0.1, 30, 270, ec=\"none\")\n",
    "patches.append(wedge)\n",
    "plt.text(pos[0, 2], pos[1, 2] - 0.15, \"Wedge\", ha=\"center\", size=14)\n",
    "\n",
    "# add a Polygon\n",
    "polygon = mpatches.RegularPolygon(pos[:, 3], 5, 0.1)\n",
    "patches.append(polygon)\n",
    "plt.text(pos[0, 3], pos[1, 3] - 0.15, \"Polygon\", ha=\"center\", size=14)\n",
    "\n",
    "#add an ellipse\n",
    "ellipse = mpatches.Ellipse(pos[:, 4], 0.2, 0.1)\n",
    "patches.append(ellipse)\n",
    "plt.text(pos[0, 4], pos[1, 4] - 0.15, \"Ellipse\", ha=\"center\", size=14)\n",
    "\n",
    "#add an arrow\n",
    "arrow = mpatches.Arrow(pos[0, 5] - 0.05, pos[1, 5] - 0.05, 0.1, 0.1, width=0.1)\n",
    "patches.append(arrow)\n",
    "plt.text(pos[0, 5], pos[1, 5] - 0.15, \"Arrow\", ha=\"center\", size=14)\n",
    "\n",
    "# add a path patch\n",
    "Path = mpath.Path\n",
    "verts = np.array([\n",
    "     (0.158, -0.257),\n",
    "     (0.035, -0.11),\n",
    "     (-0.175, 0.20),\n",
    "     (0.0375, 0.20),\n",
    "     (0.085, 0.115),\n",
    "     (0.22, 0.32),\n",
    "     (0.3, 0.005),\n",
    "     (0.20, -0.05),\n",
    "     (0.158, -0.257),\n",
    "    ])\n",
    "verts = verts - verts.mean(0)\n",
    "codes = [Path.MOVETO,\n",
    "         Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.LINETO,\n",
    "         Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.CLOSEPOLY]\n",
    "\n",
    "path = mpath.Path(verts / 2.5 + pos[:, 6], codes)\n",
    "patch = mpatches.PathPatch(path)\n",
    "patches.append(patch)\n",
    "plt.text(pos[0, 6], pos[1, 6] - 0.15, \"PathPatch\", ha=\"center\", size=14)\n",
    "\n",
    "# add a fancy box\n",
    "fancybox = mpatches.FancyBboxPatch(\n",
    "        pos[:, 7] - [0.025, 0.05], 0.05, 0.1,\n",
    "        boxstyle=mpatches.BoxStyle(\"Round\", pad=0.02))\n",
    "patches.append(fancybox)\n",
    "plt.text(pos[0, 7], pos[1, 7] - 0.15, \"FancyBoxPatch\", ha=\"center\", size=14)\n",
    "\n",
    "# add a line\n",
    "x,y = np.array([[-0.06, 0.0, 0.1], [0.05,-0.05, 0.05]])\n",
    "line = mlines.Line2D(x+pos[0, 8], y+pos[1, 8], lw=5.)\n",
    "plt.text(pos[0, 8], pos[1, 8] - 0.15, \"Line2D\", ha=\"center\", size=14)\n",
    "\n",
    "collection = PatchCollection(patches)\n",
    "ax.add_collection(collection)\n",
    "ax.add_line(line)\n",
    "ax.set_axis_off()\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Containers are objects like *Figure* and *Axes*. Containers are given primitives to draw. The plotting functions we discussed back in Parts 1 & 2 are convenience functions that generate these primitives and places them into the appropriate containers. In fact, most of those functions will return artist objects (or a list of artist objects) as well as store them into the appropriate axes container.\n",
    "\n",
    "As discussed in Part 3, there is a wide range of properties that can be defined for your plots.  These properties are processed and applied to their primitives. Ultimately, you can override anything you want just by directly setting a property to the object itself."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "fig, ax = plt.subplots(1, 1)\n",
    "lines = plt.plot([1, 2, 3, 4], [1, 2, 3, 4], 'b', [1, 2, 3, 4], [4, 3, 2, 1], 'r')\n",
    "lines[0].set(linewidth=5)\n",
    "lines[1].set(linewidth=10, alpha=0.7)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To see what properties are set for an artist, use [`getp()`](https://matplotlib.org/api/artist_api.html#functions)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "fig = plt.figure()\n",
    "print(plt.getp(fig.patch))\n",
    "plt.close(fig)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Collections\n",
    "In addition to the Figure and Axes containers, there is another special type of container called a [`Collection`](http://matplotlib.org/api/collections_api.html). A Collection usually contains a list of primitives of the same kind that should all be treated similiarly. For example, a [`CircleCollection`](http://matplotlib.org/api/collections_api.html#matplotlib.collections.CircleCollection) would have a list of [`Circle`](https://matplotlib.org/api/_as_gen/matplotlib.patches.Circle.html) objects all with the same color, size, and edge width. Individual property values for artists in the collection can also be set (in some cases)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from matplotlib.collections import LineCollection\n",
    "fig, ax = plt.subplots(1, 1)\n",
    "# A collection of 3 lines\n",
    "lc = LineCollection([[(4, 10), (16, 10)],\n",
    "                     [(2, 2), (10, 15), (6, 7)],\n",
    "                     [(14, 3), (1, 1), (3, 5)]])\n",
    "lc.set_color('r')\n",
    "lc.set_linewidth(5)\n",
    "ax.add_collection(lc)\n",
    "ax.set_xlim(0, 18)\n",
    "ax.set_ylim(0, 18)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# Now set individual properties in a collection\n",
    "fig, ax = plt.subplots(1, 1)\n",
    "lc = LineCollection([[(4, 10), (16, 10)],\n",
    "                     [(2, 2), (10, 15), (6, 7)],\n",
    "                     [(14, 3), (1, 1), (3, 5)]])\n",
    "lc.set_color(['r', 'blue', (0.2, 0.9, 0.3)])\n",
    "lc.set_linewidth([4, 3, 6])\n",
    "ax.add_collection(lc)\n",
    "ax.set_xlim(0, 18)\n",
    "ax.set_ylim(0, 18)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There are other kinds of collections that are not just simply a list of primitives, but are Artists in their own right. These special kinds of collections take advantage of various optimizations that can be assumed when rendering similar or identical things. You use these collections all the time whether you realize it or not! Markers are implemented this way (so, whenever you do `plot()` or `scatter()`, for example)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from matplotlib.collections import RegularPolyCollection\n",
    "\n",
    "fig, ax = plt.subplots(1, 1)\n",
    "offsets = np.random.rand(20, 2)\n",
    "collection = RegularPolyCollection(\n",
    "    numsides=5,  # a pentagon\n",
    "    sizes=(150,),\n",
    "    offsets=offsets,\n",
    "    transOffset=ax.transData,\n",
    "    )\n",
    "ax.add_collection(collection)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Exercise 5.1\n",
    "Give yourselves 4 gold stars!\n",
    "\n",
    "Hint: [StarPolygonCollection](http://matplotlib.org/api/collections_api.html#matplotlib.collections.StarPolygonCollection)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "%load exercises/5.1-goldstar.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from matplotlib.collections import StarPolygonCollection\n",
    "\n",
    "fig, ax = plt.subplots(1, 1)\n",
    "\n",
    "collection = StarPolygonCollection(5,\n",
    "                                   offsets=[(0.5, 0.5)],\n",
    "                                   transOffset=ax.transData)\n",
    "ax.add_collection(collection)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
